﻿using System;
using System.Reflection;

namespace Ooaavee.TestTools
{
    /// <summary>
    /// A wrapper class around a test hook.
    /// </summary>
    internal sealed class TestHookHandle : IDisposable
    {
        private readonly ITestHook _testHook;
        private readonly object[] _parameters;

        /// <summary>
        /// Initializes a new instance of the TestHookHandle class.
        /// </summary>
        /// <param name="testHook">test hook</param>
        /// <param name="parameters">parameters</param>
        /// <param name="context">ExtendedTestContext</param>
        public TestHookHandle(ITestHook testHook, object[] parameters, ExtendedTestContext context)
        {
            _testHook = testHook;
            _parameters = parameters;

            TrySetContext(_testHook, context);
        }

        /// <summary>
        /// Disposes the test hook.
        /// </summary>
        void IDisposable.Dispose()
        {
            _testHook.Dispose();
        }

        /// <summary>
        /// Executes the test hook.
        /// </summary>
        public void Run()
        {
            _testHook.Run(_parameters);
        }

        /// <summary>
        /// Tries to bind a <see cref="ExtendedTestContext"/> into the specifed object.
        /// </summary>
        /// <param name="target">target</param>
        /// <param name="context">ExtendedTestContext</param>
        private static void TrySetContext(object target, ExtendedTestContext context)
        {
            PropertyInfo property = target.GetType().GetProperty("ExtendedTestContext", BindingFlags.Public | BindingFlags.Instance);
            if (property == null)
            {
                return;
            }

            if (property.PropertyType.Equals(typeof (ExtendedTestContext)) == false)
            {
                return;
            }

            if (property.CanWrite == false)
            {
                return;
            }

            property.SetValue(target, context, null);
        }
    }
}